Things to help you get using DVM:
---------------------------------
2020/10 Added a ILIB value to .DVM files. Think of it as a version number, but
        it won't change every time I release new DVM. It will increment when I
        make changes to the internal library, or for some other reason a .DVM
        file built under a newer DVM might not be fully compatible with older
        versions.  This is to avoid problems running older applications which
        should be rebuilt or at least patch'd with DVMLIB.
2021/06 Various fixes to DVM and the DVM Micro-C compiler.

Last update: Jun 9,2021


DVM is a simple windows executable.  It does not require installation, just
run it and give it the name of a .DVM application program to load and run.
Any additional options on the command line will be passed to the application
just as if were run directly.

The .DVM extension is not required. '.DVM' will be assumed if no extension
is given in the application name.

If the name contains a path, DVM will attempt to load it from there.

If no path is given, DVM will look to see if the .DVM file exists in
the current directory, and if so will run it from there.

If not, it will next check the directory where DVM.EXE is located !IF IT CAN!
I don't know if it's Windows, LCC or both, but an executable cannot ALWAYS
determine where it came from.  The argv[0] passed by the system which should
contain the full program path - DOES if the executable was launched by
"clicking" it ... but if run from the command line, argv[0] only has what
was actually typed - If a path was typed it will be there - if only "DVM", was
typed with the executable having been found/launched by windows searching the
directories laid out in PATH environment variable - NONE of this information
is supplied.

A partial path relative to the current directory is enough for DVM to locate
it's files, but I don't recommend this because it makes DVM set argv[0] of
any .DVM programs it runs to that partial path. I urge you to launch DVM with
argv[0] containing the full path. One easy way to do this is to put DVM.BAT
in your search path which launches DVM.EXE by specifying a full path.

This is the main reason I added...

If DVM cannot otherwise find the .DVM file, it will check to see if the
environment variable "DVM" exists, and if so, treats it like a command PATH,
looking for it's application there.  This may have multiple directories
seperated by ';', and DVM will look in each one. This environment variable
may also used by some applications, for example Micro-C's CC commands will
look in the to first directory identified there if MCDIR is not defined.

If an application performs getenv("DVM", ...) and the environment variable
"DVM" does not exist, DVM will return it's home directory if it was able to
determine it, otherwise getenv() will return 0.
 This makes it easy to make DVM work from anywhere on the command line
 without having to set ANY environment variables.  Simply put DVM.BAT
 somewhere in your path containing:
    @echo OFF
    C:\full\path\to\DVM.EXE %1 %2 %3 %4 %5 %6 %7 %8 %9



This DVM distribution includes:

    DVMNOTES.TXT<- This file
    DVM.TXT     <- Main DVM documentation
    DVMLIB.TXT  <- Describes the DVMLIB utility
    DVM.EXE     <- The DVM executable for windows
    SETUP.BAT   <- You can click this to run:
    SETUP.DVM   <- Helps get DVM integrated on a system.
    DVMLIB.DVM  <- Can patch a .DVM to use a new library layout.
    ARGS.DVM    <- Lets you test/see what Windows does to command arguments.
    EDT.DVM     <- My EDT editor
    EDT.TXT     <- Documentation for ""
    VLT.DVM     <- View large text files (good to see docs) use '?' for help.
        ; These were DOS programs.  They (and it seems the LCC TURBO-C video
        ; functions) expect a DOS 80x25 text screen.
        ; For best results: Under properties for your command window, select
        ; a layout of 80x25 and pick a suitable font size.
        ; Note: Set both "window size" and "screen buffer size" to 80x25,
        ;  otherwise LCC does not always scroll properly.

Windows Integration:
--------------------
I have tested DVM under WinXP, Wim7 and Win10. The following notes are from
Win7 but I'd assume similar information for the others.

You can make a DVM program run by "clicking" by setting up a shortcut to the
DVM.EXE executable, then using it's "properties", modify it to include the
desired application name and operands in "Target".

It's a good idea to setup the DVM environment variable to let DVM know where
it's home directory and applications are - On Win7 you can do this from the
"Advanced" tab of "System Protection" - you can get there by right-clicking
"computer" -> Properties.

You can make it so you can run .DVM files just be clicking them directly
with the windows commands (will require a CMD with admin privilege):
    ASSOC .DVM=DVM
    FTYPE DVM={insert full path}dvm.exe %1 %*

You can also run them from the command line just by typing the filename,
however you will have to provide the .DVM extension. If you want windows
to be able to run them without having to type the extension:
    set PATHEXT=.DVM;%PATHEXT%

Some of my software accepts command arguments in the form: 'text=text'.  For
example, my compiler allows you to preset #define symbols this way.   ie:
' CC pgm NAME=Dave ' will behave as if the line ' #define NAME Dave ' was
in the source file. This worked well under DOS and Windows up to XP-Win7/32,
but Win64 does not take '=' in command arguments, treating the above as if
'NAME' and 'DAVE' were two distinct arguments without the '='.  There is a
work-around, you have quote the argument, so the above command becomes:
 ' CC pgm "NAME=Dave" '     I have provided ARGS.DVM which will let you test 
and see what exactly your version of Windows does to command arguments.


Temporary files in RAM:
-----------------------
DVM has a very basic method of using RAM for large temp. storage and makes it
accessible though the file system. I added this capability so that you wouldn't
have to deal with setting up storage for the temp files created/deleted during
the compiling process.  Once I got it working, I decided that it was useful
enough that others might want to use it.  For more information refer to the
RDsetup() library function documented below.


DVM internal library:
---------------------
Note I created DVM mainly to make it easy to move years worth of software I
had written for DOS to other platforms, consequently the library looks much
like the Micro-C/PC DOS library!  -  note that this would not be applicable
if you use DVM in a product (unless you wanted it to).  A DVM library can be
made to perform any functions and in any way that you like.

My Micro-C DVM toolset (which can be downloaded from my site) includes complete
documentation for the Micro-C library which is built into DVM.

The following functions are NOT yet included in the DVM library.  Many of
them use DOS features/functions for which I am not familiar with Windows
equivalents, or hardware access which is not available under Windows.
A few were based on the code generated by my DOS compiler and I do not know
necessary details of LCCwin32, and some are just things I don't use a lot and
haven't taken the time to do yet:

    bsearch     clearerr    close       create      dup         dup2
    ferror      freopen     in          inw         isacon      isadev
    isatty      lgetc       lgets       lprintf     lputc       lputs
    lrewind     lscanf      lsearch     lseek       ltell       open
    out         outw        qsort       read        realloc     rename
    setbuf      strcspn     stricmp     strncat     strncmp     strnicmp
    strnset     strpbrk     strrchr     strspn      strtok      write
    alloca      cbreak      Cclose      Cgetc       Copen       copy_seg
    cpu         Cputc       Csignals    Ctestc      disable     enable
    get_attr    get_cs      get_ds      get_es      get_vector  int86
    intr        joystick    resize_seg  restore_video           save_video
    set_attr    set_date    set_drive   set_es      set_time    set_vector
    sound       sound_off   tsr         vclear_box  vcleol      vcleos
    vclscr      vcursor_block           vcursor_line            vcursor_off
    vdraw_box   version     vgetc       vgets       vgotoxy     vmenu
    vmessage    vopen       vprintf     vputc       vputf       vputs
    vtstc       vupdatexy   wcleol      w_cleol     wcleow      w_cleow
    wclose      w_close     wclwin      w_clwin     wcursor_block
    wcursor_line            wcursor_off wform       wgetc       w_getc
    wgets       wgotoxy     w_gotoxy    wmenu       wmessage    wopen
    wprintf     w_printf    wputc       w_putc      wputf       wputs
    w_puts      wtstc       w_tstc      wupdatexy   w_updatexy  lrg_arc
    lrg_blit    lrg_box     lrg_fbox    lrg_circle  lrg_fcircle lrg_close
    lrg_delay   lrg_draw    lrg_erase   lrg_fill    lrg_getpal  lrg_setpal
    lrg_hline   lrg_vline   lrg_line    lrg_open    lrg_plot    lrg_printf
    lrg_putc    lrg_retrace lrg_scale   hrg_arc     hrg_box     hrg_fbox
    hrg_circle  hrg_fcircle hrg_close   hrg_delay   hrg_fill    hrg_getpal
    hrg_setpal  hrg_hline   hrg_vline   hrg_line    hrg_open    hrg_plot
    hrg_printf  hrg_putc    hrg_puts    hrg_retrace hrg_scale

If there is something missing that you really want, please let me know, and I
will look into providing it.


The following functions have been added in the DVM library:

void halt(unsigned rc)      = Halt VM with return code
    = Similar to exit() except all programs are stopped.

void sleep(unsigned ms)     = Another name for delay()

void find_close(void)
    LCC's findfiles() does not do one at a time like my find_*() functions.
    It returns all the filenames at once by malloc()ing a large array which
    you should free when finished with the list of files.  My library will
    automatically release it if you find_next() to the end of the list, or
    perform another find_first() but otherwise this memory will hang around.
    If you want to release it, call find_close().

unsigned RDsetup(char letter, unsigned size)
  = Establishes temp storage accessible through file system (RamDrive)
    letter is letter for drive, note that it IS case sensitive!
        ie: if you RDinit('Y', 1000) you can access host files with 'y:'
    size is RAMdrive size in 256 byte sectors (max 2047) x256=512k
    if either letter or size is 0 (zero) RAMdrive is released.
    Only supports 10 files which MUST be named '0' - '9'.
    No subdirectories are supported.
    Not all file operations are supported, only:
        fopen(), fclose(), rewind(), delete(),
        putc(), fputs(), fput(), fwrite(), fprintf(),
        getc(), fgets(), fget(), fread(), fscanf();

unsigned MemReadCode1(unsigned address) = Read byte from code memory
unsigned MemReadCode2(unsigned addr)    = Read word from code memory
  = In SMALL model, the CODE portion of the .DVM file is invisible to
    the executing application other than that instructions are fetched
    from there.  There may be times that you would like to put large
    static data tables in code space, freeing up data space.
    These functions provide read access to code memory.


These following functions provide access to the LCC video functions which
are identified as based on Borland TURBO-C.  They are nowhere as capable as
my text windowing library offering, but at least it's something to allow
basic video function:

// Video function: see DVMVIDEO.H for special values
unsigned Vinit(char co)     = Init for 24x80 video
  = returns (#cols*100)+#lines
void Vclose(void)           = Terminate video
void Vgotoxy(unsigned x, unsigned y)
  = Position the cursor
void Vcleol(void)           = Clear from cursor to end of line
void Vcleos(void)           = Clear from cursor to end of screen
void Vclscr(void)           = Clear entire screen
void Vcursor(unsigned type) = Set the cursor type
  = type: 0=None, 1=Solid, 2=Line
unsigned Vgetc(void)        = Get key with 16bit code for special keys
unsigned Vgetk(void)        = "" but translates keypad to be same as !keypad
unsigned Vgets(char *buffer, unsigned length)
  = Get string
    length: bits 0-6 indicate maximum length
            bits 8-15 !0 = return on special keys
            bit 8 = Restore input buffer on special keys
            bit 9 = return key code instead of length
    arrows/home/end = move
    backspace       = delete previous
    ins             = Toggle insert mode
    ENTER           = exit returning length (or key)
    ESC             = exit returning 0xFFFF
void Vputc(char c)      = Write character to video screen
void Vputs(unsigned *s) = Write string to video screen
register Vprintf(...)   = Formatted print to video screen
  = Should use these when using video lib as they track cursor position
    Also prevent printing in lower-right corner which causes LCC library
    to scroll the screen.
void Vcolor(unsigned co)    = Set background/foreground color
void VFcolor(unsigned col)  = Set foreground color only
void VBcolor(unsigned co)   = Set background color only


Quickstart for DVM and Micro-C DVM
----------------------------------
To try building and running C programs on DVM, I recommend something like:
    Download DVM.ZIP, MCDVM.ZIP and EXAMPLEC.ZIP from my site.
    Unpack all three .ZIPS to: DVM\, MC\ and EXAMPLEC\
    Copy the content of MC\ and EXAMPLEC\ to DVM\
        xcopy/s MC DVM              (MC\ can be removed afterward)
        xcopy/s EXAMPLEC DVM        (EXAMPLEC\ can be removed afterward)
    Go to DVM\
        cd DVM
    Build HELLO.DVM from HELLO.C
        dvm cc hello
    Run HELLO.DVM
        dvm hello
